﻿namespace LiteBlog.Repositories
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Xml.Linq;

    using LiteBlog.Common;
    using LiteBlog.Common.Components;
    using LiteBlog.Common.Entities;
    using LiteBlog.Common.Enums;
    using LiteBlog.Repositories.Helpers;
    using LiteBlog.Repositories.Contracts;
    using LiteBlog.Repositories.Framework;
    using LiteBlog.Repositories.Common;

    public class DraftRepository : DataAccess, IRepository
    {
        private XElement _root;
        public DraftRepository(IDataContext context, IXmlHelper xmlHelper) : base(context, xmlHelper)
        {
            _path = context.GetPath(DataStoreType.Draft, null);
            _root = _xmlHelper.Load(this._path);
        }

        internal List<PostInfo> Get()
        {
            var postInfos = new List<PostInfo>();
            foreach (var draftElem in _root.Elements(Elem.Draft))
            {
                var postInfo = new PostInfo();
                postInfo.Title = draftElem.Attribute(Attr.Title).Value;
                postInfo.FileID = draftElem.Attribute(Attr.FileId).Value;
                if(draftElem.Attribute(Attr.Scheduled) != null)
                {
                    postInfo.FormattedTime = draftElem.Attribute(Attr.Scheduled).Value;
                    postInfo.Time = DateTime.ParseExact(draftElem.Attribute(Attr.Scheduled).Value,
                                                        Constants.DateTimeFormat,
                                                        CultureInfo.InvariantCulture);
                    postInfo.Type = PostType.Scheduled;
                }
                else
                {
                    postInfo.FormattedTime = draftElem.Attribute(Attr.Date).Value;
                    postInfo.Time = DateTime.ParseExact(draftElem.Attribute(Attr.Date).Value, 
                                                        Constants.DateTimeFormat, 
                                                        CultureInfo.InvariantCulture);
                    postInfo.Type = PostType.Draft;
                }
               
                postInfos.Add(postInfo);
            }

            return postInfos;
        }

        internal void Create(string draftId, string fileId, string title, List<Category> categories, DateTime? time = null)
        {
            if (!time.HasValue)
            {
                time = DateTimeHelper.Now;
            }
            var draftElem = new XElement(
                "Draft",
                new XAttribute(Attr.FileId, draftId),
                new XAttribute(Attr.PublishedFileId, fileId),
                new XAttribute(Attr.Title, title),
                new XAttribute(Attr.CatId, GetCsvIds(categories)),
                new XAttribute(
                    Attr.Date,
                    time.Value.ToString(Constants.DateTimeFormat, CultureInfo.InvariantCulture)));
            _root.Add(draftElem);
            _xmlHelper.Save(_root, _path);
        }

        internal void Update(PostInfo postInfo)
        {
            var draftElem = _root.Elements(Elem.Draft)
                                .SingleOrDefault(elem => 
                                    (string)elem.Attribute(Attr.FileId) == postInfo.FileID);
            if (draftElem != null)
            {
                draftElem.SetAttributeValue(Attr.Title, postInfo.Title);
                draftElem.SetAttributeValue(Attr.Date, 
                                            postInfo.Time.ToString(Constants.DateTimeFormat, 
                                                                   CultureInfo.InvariantCulture));
                draftElem.SetAttributeValue(Attr.CatId, GetCsvIds(postInfo.Categories));
            }
            _xmlHelper.Save(_root, _path);
        }

        internal void Delete(string draftId)
        {
            var draftElem = _root.Elements(Elem.Draft)
                                .SingleOrDefault(elem => 
                                    (string)elem.Attribute(Attr.FileId) == draftId);
            if (draftElem != null)
                draftElem.Remove();
            _xmlHelper.Save(_root, _path);
        }

        internal string GetDraftIdForPublishedPost(string fileId)
        {
            var draftElem = _root.Elements(Elem.Draft)
                                .SingleOrDefault(elem => 
                                    (string)elem.Attribute(Attr.PublishedFileId) == fileId);
            return draftElem != null ? draftElem.Attribute(Attr.FileId).Value : string.Empty;
        }


        internal void Schedule(string draftId, DateTime publishDate)
        {
            var draftElem = _root.Elements(Elem.Draft)
                                .SingleOrDefault(elem => 
                                    (string)elem.Attribute(Attr.FileId) == draftId);

            if (draftElem != null)
            {
                draftElem.SetAttributeValue(Attr.Scheduled, 
                                            publishDate.ToString(Constants.DateTimeFormat, 
                                                                CultureInfo.InvariantCulture));
            }

            _xmlHelper.Save(_root, _path);
        }   

        internal List<PostInfo> GetScheduled()
        {
            var postInfos = new List<PostInfo>();
            var draftElems = _root.Elements(Elem.Draft)
                                  .Where(elem => elem.Attribute(Attr.Scheduled) != null);

            foreach (XElement draftElem in draftElems)
            {
                var postInfo = new PostInfo();
                postInfo.Title = draftElem.Attribute(Attr.Title).Value;
                postInfo.FileID = draftElem.Attribute(Attr.FileId).Value;

                postInfo.Time = DateTime.ParseExact(
                    draftElem.Attribute(Attr.Scheduled).Value,
                    Constants.DateTimeFormat,
                    CultureInfo.InvariantCulture);

                postInfo.Type = PostType.Scheduled;

                postInfos.Add(postInfo);
            }

            return postInfos;
        }

     

        private string GetCsvIds(List<Category> categories)
        {
            string csvIds = string.Empty;
            if (categories != null && categories.Count > 0)
                csvIds = categories.Select(c => c.CatID).Aggregate((cur, next) => cur + "," + next);
            return csvIds;
        }
    }
}